//
// Created by LONG on 2020/10/18.
//


#include <stdio.h>
#include "../../include/utils/fsm.h"
#include "../../include/utils/hashTable.h"
#include "../../include/utils/hashFunc.h"

#define FSM_LOG(SM, TYPE, FMT, ARGS...) \
do{\
    if (sm->logCallback)\
    {\
        sm->logCallback(TYPE, FMT, ##ARGS);\
    }\
}while(0)

struct FsmStateTrans
{
    uint32_t procRslt;
    uint32_t nextState;
    const char *nextStateStr;
};

struct FsmEventHandle
{
    uint32_t event;
    const char *eventStr;
    FsmEventHandleFunc handleFunc;
    S_HashTable *transTable; /* S_FsmStateTrans */
};

struct FsmState
{
    uint32_t state;
    const char *stateStr;
    S_FsmEventHandle *defaultHandle;
    S_HashTable *eventTable; /* S_FsmEventHandle */
};

struct Fsm
{
    const char *smIdStr;
    uint32_t initState;
    FsmLogCallback logCallback;
    S_HashTable *stateTable; /* S_FsmState */
};

struct FsmInst
{
    S_Fsm *sm;
    uint32_t currState;
    char *instIdStr;
};

void FSM_FinalTrans(S_FsmStateTrans *stateTrans)
{
    OS_MemFree(stateTrans);
}

void FSM_FinalEvent(S_FsmEventHandle *eventHandle)
{
    S_HashNodeKeyVal *keyValue;
    S_HashTableIter iter;

    HashTable_Iterate(eventHandle->transTable, &iter);
    while (HashTableIter_HasMore(&iter))
    {
        keyValue = HashTableIter_Next(&iter);
        FSM_FinalTrans((S_FsmStateTrans *)keyValue->data);
    }
    HashTable_Destroy(eventHandle->transTable);
    OS_MemFree(eventHandle);
}

void FSM_FinalState(S_FsmState *smState)
{
    S_HashNodeKeyVal *keyValue;
    S_HashTableIter iter;

    HashTable_Iterate(smState->eventTable, &iter);
    while (HashTableIter_HasMore(&iter))
    {
        keyValue = HashTableIter_Next(&iter);
        FSM_FinalEvent((S_FsmEventHandle *)keyValue->data);
    }
    if (smState->defaultHandle)
    {
        FSM_FinalEvent(smState->defaultHandle);
    }
    HashTable_Destroy(smState->eventTable);
    OS_MemFree(smState);
}

void FSM_Final(S_Fsm *sm)
{
    S_HashNodeKeyVal *keyValue;
    S_HashTableIter iter;

    HashTable_Iterate(sm->stateTable, &iter);
    while (HashTableIter_HasMore(&iter))
    {
        keyValue = HashTableIter_Next(&iter);
        FSM_FinalState((S_FsmState *)keyValue->data);
    }
    HashTable_Destroy(sm->stateTable);
    OS_MemFree(sm);
}

void FSM_SetLogCallback(S_Fsm *sm, FsmLogCallback callback)
{
    sm->logCallback = callback;
}

S_FsmInst* FSM_INST_Init(S_Fsm *sm, const char* instIdStr)
{
    S_FsmInst *smInst;

    smInst = OS_MemCalloc(1, sizeof(S_FsmInst));
    if (NULL == smInst)
    {
        return NULL;
    }
    smInst->sm = sm;
    smInst->currState = sm->initState;
    smInst->instIdStr = strdup(instIdStr);

    return smInst;
}

void FSM_INST_Final(S_FsmInst *smInst)
{
    free(smInst->instIdStr);
    OS_MemFree(smInst);
}

void FSM_INST_Reset(S_FsmInst *smInst)
{
    smInst->currState = smInst->sm->initState;
}

uint32_t FSM_INST_GetState(S_FsmInst *smInst)
{
    return smInst->currState;
}

void FSM_INST_SetState(S_FsmInst *smInst, uint32_t state)
{
    smInst->currState = state;
}

int32_t FSM_INST_HandleEventImpl(S_FsmInst *smInst, S_FsmEventContext *evtCtxt, S_FsmHandleResult *result)
{
    S_Fsm *sm;
    S_FsmState *sm_state;
    S_HashNodeKeyVal *hashKeyVal;
    S_FsmEventHandle *eventHandle;
    S_FsmStateTrans *stateTrans;

    sm = smInst->sm;

    hashKeyVal = HashTable_Lookup(sm->stateTable, &smInst->currState);
    sm_state = hashKeyVal ? hashKeyVal->data : NULL;
    if (NULL == sm_state)
    {
        FSM_LOG(sm, FSM_LOG_TYPE_ERR, "FSM[%s] INST[%s]: Can not find state[%u]\n", sm->smIdStr, smInst->instIdStr, smInst->currState);
        return FSM_RC_STATE_ERR;
    }

    hashKeyVal = HashTable_Lookup(sm_state->eventTable, &evtCtxt->event);
    eventHandle = hashKeyVal ? hashKeyVal->data : NULL;
    if (NULL == eventHandle)
    {
        eventHandle = sm_state->defaultHandle;
    }
    if (NULL == eventHandle)
    {
        FSM_LOG(sm, FSM_LOG_TYPE_ERR, "FSM[%s] INST[%s]: %s Can not find event[%u], and default handle is NULL\n",
            sm->smIdStr, smInst->instIdStr, sm_state->stateStr, evtCtxt->event);
        return FSM_RC_EVENT_ERR;
    }

    /* 处理事件 */
    eventHandle->handleFunc(smInst->currState, evtCtxt, result);

    hashKeyVal = HashTable_Lookup(eventHandle->transTable, &result->procRslt);
    stateTrans = hashKeyVal ? hashKeyVal->data : NULL;
    if (NULL == stateTrans)
    {
        FSM_LOG(sm, FSM_LOG_TYPE_ERR, "FSM[%s] INST[%s]: %s[%s] Can not find trans[%u]\n",
            sm->smIdStr, smInst->instIdStr, sm_state->stateStr, eventHandle->eventStr, result->procRslt);
        return FSM_RC_TRANS_ERR;
    }

    /* 状态转移 */
    smInst->currState = stateTrans->nextState;

    if (!result->newEventInd)
    {
        FSM_LOG(sm, FSM_LOG_TYPE_STATE_TRANS, "FSM[%s] INST[%s]: %s[%s(%u)] --> %s\n",
            sm->smIdStr, smInst->instIdStr, sm_state->stateStr, eventHandle->eventStr, evtCtxt->event, stateTrans->nextStateStr);
    }
    else
    {
        FSM_LOG(sm, FSM_LOG_TYPE_STATE_TRANS, "FSM[%s] INST[%s]: %s[%s(%u)] --> %s, newEvent(%u)\n",
            sm->smIdStr, smInst->instIdStr, sm_state->stateStr, eventHandle->eventStr, evtCtxt->event, stateTrans->nextStateStr, result->newEvent);
    }

    return FSM_RC_OK;
}

int32_t FSM_INST_HandleEvent(S_FsmInst *smInst, S_FsmEventContext *evtCtxt)
{
    int32_t rc;
    S_FsmEventContext ctxt;
    S_FsmHandleResult result;

    memcpy(&ctxt, evtCtxt, sizeof(S_FsmEventContext));

    do {
        result.newEventInd = 0;
        rc = FSM_INST_HandleEventImpl(smInst, &ctxt, &result);
        if (FSM_RC_OK != rc)
        {
            return rc;
        }
        ctxt.event = result.newEvent;
        ctxt.context = result.newContext;
    } while (result.newEventInd);

    return FSM_RC_OK;
}

S_Fsm* FSM_IFUNC_InitFsm(const char* fsmId, uint32_t initState)
{
    S_Fsm *sm;

    sm = (S_Fsm *)OS_MemCalloc(1, sizeof(S_Fsm));
    if (NULL == sm)
    {
        return NULL;
    }

    sm->stateTable = HashTable_Create(FSM_STATE_NUM_MAX, Hash_Uint32, Equal_Uint32);
    if (NULL == sm->stateTable)
    {
        OS_MemFree(sm);
        return NULL;
    }

    sm->smIdStr = fsmId;
    sm->initState = initState;

    return sm;
}

S_FsmState* FSM_IFUNC_InitState(S_Fsm *sm, uint32_t state, const char* stateStr)
{
    int32_t rc;
    S_FsmState *smState;

    /* 检查是否已经存在 */
    if (HashTable_Lookup(sm->stateTable, &state))
    {
        return NULL;
    }

    smState = (S_FsmState *)OS_MemCalloc(1, sizeof(S_FsmState));
    smState->state = state;
    smState->stateStr = stateStr;
    smState->eventTable = HashTable_Create(FSM_EVENT_NUM_MAX, Hash_Uint32, Equal_Uint32);
    if (NULL == smState->eventTable)
    {
        return NULL;
    }

    rc = HashTable_Insert(sm->stateTable, &smState->state, smState);
    if (FSM_RC_OK != rc)
    {
        return NULL;
    }

    return smState;
}

S_FsmEventHandle* FSM_IFUNC_InitEventHandle(S_FsmState *smState, uint32_t event, const char* eventStr, FsmEventHandleFunc handleFunc)
{
    int32_t rc;
    S_FsmEventHandle *smEventHandle;

    /* 检查是否已经存在 */
    if (HashTable_Lookup(smState->eventTable, &event))
    {
        return NULL;
    }

    smEventHandle = (S_FsmEventHandle *)OS_MemCalloc(1, sizeof(S_FsmEventHandle));
    smEventHandle->event = event;
    smEventHandle->eventStr = eventStr;
    smEventHandle->handleFunc = handleFunc;
    smEventHandle->transTable = HashTable_Create(FSM_TRANS_NUM_MAX, Hash_Uint32, Equal_Uint32);
    if (NULL == smEventHandle->transTable)
    {
        return NULL;
    }

    rc = HashTable_Insert(smState->eventTable, &smEventHandle->event, smEventHandle);
    if (FSM_RC_OK != rc)
    {
        return NULL;
    }

    return smEventHandle;
}

S_FsmEventHandle* FSM_IFUNC_InitDefaultEventHandle(S_FsmState *smState, FsmEventHandleFunc handleFunc)
{
    S_FsmEventHandle *smEventHandle;

    smEventHandle = (S_FsmEventHandle *)OS_MemCalloc(1, sizeof(S_FsmEventHandle));
    smEventHandle->event = 0xFFFFFFFF;
    smEventHandle->eventStr = "";
    smEventHandle->handleFunc = handleFunc;
    smEventHandle->transTable = HashTable_Create(FSM_TRANS_NUM_MAX, Hash_Uint32, Equal_Uint32);
    if (NULL == smEventHandle->transTable)
    {
        return NULL;
    }

    smState->defaultHandle = smEventHandle;

    return smEventHandle;
}

S_FsmStateTrans* FSM_IFUNC_InitStateTrans(S_FsmEventHandle *smEventHandle, uint32_t procRslt, uint32_t nextState, const char* nextStateStr)
{
    int32_t rc;
    S_FsmStateTrans *smStateTrans;

    /* 检查是否已经存在 */
    if (HashTable_Lookup(smEventHandle->transTable, &procRslt))
    {
        return NULL;
    }

    smStateTrans = (S_FsmStateTrans *)OS_MemCalloc(1, sizeof(S_FsmStateTrans));
    smStateTrans->procRslt = procRslt;
    smStateTrans->nextState = nextState;
    smStateTrans->nextStateStr = nextStateStr;

    rc = HashTable_Insert(smEventHandle->transTable, &smStateTrans->procRslt, smStateTrans);
    if (FSM_RC_OK != rc)
    {
        return NULL;
    }

    return smStateTrans;
}